package pack1;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;


public class Node implements Comparable
{
	public Float AverageDelta = null;
	public int CountOfAverageTimes = 0;
	
	public Hashtable<Node, Float> m_incommingLinks = new Hashtable<Node, Float>(),
	m_outgoingLinks = new Hashtable<Node, Float>();
	public int m_Index ;
	
	public ArrayList<Node> m_inNeighbors = new ArrayList<Node>(); 
	//containing target nodes with simrank score 
	private Hashtable<Node, Float> m_simRankCurrentScores = new Hashtable<Node, Float>(),
	m_deltas = new Hashtable<Node, Float>();
	
	public ArrayList<Node> m_cachedSelectedNeighbors;
	public Node(int index)
	{
		m_Index = index;
		AddInLink(this, 1);
	}
	public void SkipAndIncreaseAverageDelta(float increment)
	{		
		AverageDelta +=increment;
		CountOfAverageTimes++;
	}
	public void setSimRank(Node other,float value)
	{
		float oldValue = 0;
		if(m_simRankCurrentScores.contains(other))
			oldValue = m_simRankCurrentScores.get(other);
		//store value
		m_simRankCurrentScores.put(other, value);
		
		//store delta
		setDelta(other, value-oldValue);
	}
	public double getAverageScoreOfNeighbors()
	{
		Enumeration<Float> scores = m_incommingLinks.elements();
		double avgScore, totalScore =0;
		int count_ofNeighbors = 0;

		while(scores.hasMoreElements())
		{
			totalScore+=scores.nextElement();			
		}
			
		Enumeration<Float> deltas = m_deltas.elements();
		
		double avgDelta,totalDelta=0;
		while(deltas.hasMoreElements())
		{	
			totalDelta+= deltas.nextElement();
			count_ofNeighbors++;
		}
		if(count_ofNeighbors==0)
			return 0;
		
		avgScore = totalScore/count_ofNeighbors;
		avgDelta = totalDelta/count_ofNeighbors;
		
		return avgScore*avgDelta;
	}
	public void selectNodesAbove()
	{
		double avg = getAverageScoreOfNeighbors();
		Enumeration<Node> keys= m_incommingLinks.keys();
		ArrayList<Node> list = new ArrayList<Node>();
		Node temp ;
		while(keys.hasMoreElements()) 
		{
			temp = keys.nextElement();
			if(m_incommingLinks.get(temp)>=avg)
				list.add(temp);
		}
		m_cachedSelectedNeighbors = list;
		//return list;
		
	}
	public void setDelta(Node other, float delta)
	{
		m_deltas.put(other,delta);
		//incremental average
		if(CountOfAverageTimes==0)
			AverageDelta = delta;
		else
		{
			AverageDelta = AverageDelta*CountOfAverageTimes + delta / (CountOfAverageTimes+1);
		}
		CountOfAverageTimes++;
	}
	
	public void InitSimRank(ArrayList<Node> nodes)
	{
		for (Node n : nodes) {
			if(n==this)
				{
				m_simRankCurrentScores.put(this, new Float(1));
				//m_deltas .put(this, new Float(0));
				}
			else
			{
				m_simRankCurrentScores.put(n, new Float(0));
				
			}
		}
	}
	public Hashtable<Node, Float> GetSimRankMap()
	{
		return m_simRankCurrentScores;
	}
	
	public void AddInLink(Node sender , float value)
	{
		m_inNeighbors.add(sender);
		m_incommingLinks.put(sender, value);
	}
	public void AddOutLink(Node sender , float value)
	{
		m_outgoingLinks.put(sender, value);
	}
	
	public int getInDegree()
	{
		return m_incommingLinks.size();
	}
	public int getOutDegree()
	{
		return m_outgoingLinks.size();
	}

	public Node[] getInNeighbors()
	{
		Node[] temp = new Node[m_inNeighbors.size()];
		m_inNeighbors.toArray(temp);
		return temp;
	}
	public float getScoreForNode(Node other)
	{
		if(! m_incommingLinks.containsKey(other))
			return 0;
		else return m_incommingLinks.get(other);
	}
	public float getDeltaForNode(Node other)
	{
		if(!m_deltas.containsKey(other))
			return 0;
		else 
			if(this ==other )
				return 0;
			else 
				return m_deltas.get(other);
	}
	@Override
	public int compareTo(Object other) {
		if( other instanceof Node)
		{
		
		return this.m_Index- ((Node)other).m_Index;
		}
		else 
			return -1;
	}
	@Override
	public boolean equals(Object other) {
		if( other instanceof Node)
		{
			return this.m_Index==((Node)other).m_Index;
		}
		else
			return false;
	}
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return m_Index;
	}
}
